﻿using System;
using System.Reflection;
using Autofac;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Zinnia.AotofacTest
{
    //参考文档 http://www.cnblogs.com/wolegequ/archive/2012/06/02/2531945.html

    /// <summary>
    /// AutoFac常用注册方法
    /// </summary>
    public sealed class AutoFacRegister
    {
        /// <summary>
        /// 注册实例类
        /// </summary>
        public static void can_resolve_myclass()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<MyClass>();

            IContainer container = builder.Build();
            var myclass = container.Resolve<MyClass>();
            Assert.IsNotNull(myclass);
        }
        /// <summary>
        /// 注册接口
        /// </summary>
        public static void register_as_interface()
        {
            var builder = new ContainerBuilder();
            builder.Register(c => new MyClass()).As<IMyInterface>();

            IContainer container = builder.Build();
            Assert.IsNotNull(container.Resolve<IMyInterface>());
            Assert.IsNull(container.Resolve<MyClass>());//未注册类型异常
        }
        /// <summary>
        /// 带构造函数的注册
        /// </summary>
        public static void register_with_parameter()
        {
            var builder = new ContainerBuilder();
            builder.Register(c => new MyParameter());
            builder.Register(c => new MyClass(c.Resolve<MyParameter>()));
            IContainer container = builder.Build();
            Assert.IsNotNull(container.Resolve<MyClass>());
        }
        /// <summary>
        /// 带属性赋值的构造函数
        /// </summary>
        public static void register_with_property()
        {
            var builder = new ContainerBuilder();
            builder.Register(c => new MyProperty());
            builder.Register(
                c => new MyClass()
                {
                    Property = c.Resolve<MyProperty>()
                });
            IContainer container = builder.Build();
            var myClass = container.Resolve<MyClass>();
            Assert.IsNotNull(myClass);
            Assert.IsNotNull(myClass.Property);
        }
        /// <summary>
        /// 分离类的创建和使用，可以根据输入参数（NamedParameter）动态的选择实现类(工厂模式)
        /// </summary>
        public static void select_an_implementer_based_on_parameter_value()
        {
            var builder = new ContainerBuilder();
            builder.Register<IRepository>((c, p) =>
            {
                var type = p.Named<string>("type");
                if (type == "test")
                {
                    return new TestRepository();
                }
                else
                {
                    return new DbRepository();
                }
            }).As<IRepository>();

            IContainer container = builder.Build();
            var repository = container.Resolve<IRepository>(new NamedParameter("type", "test"));
            Assert.AreEqual(typeof(TestRepository), repository.GetType());
        }
        /// <summary>
        /// 用一个实例来注册，比如用在单例模式情况下
        /// </summary>
        public static void register_with_instance()
        {
            var builder = new ContainerBuilder();
            builder.RegisterInstance(MyInstance.Instance).ExternallyOwned();
            IContainer container = builder.Build();
            var myInstance1 = container.Resolve<MyInstance>();
            var myInstance2 = container.Resolve<MyInstance>();
            Assert.AreEqual(myInstance1, myInstance2);
        }
        /// <summary>
        /// 注册泛型
        /// </summary>
        public static void register_open_generic()
        {
            var builder = new ContainerBuilder();
            builder.RegisterGeneric(typeof(MyList<>));
            IContainer container = builder.Build();
            var myIntList = container.Resolve<MyList<int>>();
            Assert.IsNotNull(myIntList);
            var myStringList = container.Resolve<MyList<string>>();
            Assert.IsNotNull(myStringList);
        }
        /// <summary>
        /// 覆盖之前的注册
        /// </summary>
        public static void register_order()
        {
            var containerBuilder = new ContainerBuilder();
            containerBuilder.RegisterType<DbRepository>().As<IRepository>();
            containerBuilder.RegisterType<TestRepository>().As<IRepository>();

            IContainer container = containerBuilder.Build();
            var repository = container.Resolve<IRepository>();
            Assert.AreEqual(typeof(TestRepository), repository.GetType());
        }
        /// <summary>
        /// 保留原有注册
        /// </summary>
        public static void register_order_defaults()
        {
            var containerBuilder = new ContainerBuilder();
            containerBuilder.RegisterType<DbRepository>().As<IRepository>();
            containerBuilder.RegisterType<TestRepository>().As<IRepository>().PreserveExistingDefaults();

            IContainer container = containerBuilder.Build();
            var repository = container.Resolve<IRepository>();
            Assert.AreEqual(typeof(DbRepository), repository.GetType());
        }
        /// <summary>
        /// 使用Name来代替As进行注册
        /// </summary>
        public static void register_with_name()
        {
            var containerBuilder = new ContainerBuilder();
            containerBuilder.RegisterType<DbRepository>().Named<IRepository>("DB");
            containerBuilder.RegisterType<TestRepository>().Named<IRepository>("Test");

            IContainer container = containerBuilder.Build();
            var dbRepository = container.ResolveNamed<IRepository>("DB");
            var testRepository = container.ResolveNamed<IRepository>("Test");
            Assert.AreEqual(typeof(DbRepository), dbRepository.GetType());
            Assert.AreEqual(typeof(TestRepository), testRepository.GetType());
        }
        /// <summary>
        /// 多个构造函数，注册制定的某一个来实现
        /// </summary>
        public static void choose_constructors()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<MyParameter>();
            builder.RegisterType<MyClass>().UsingConstructor(typeof(MyParameter));
            IContainer container = builder.Build();
            var myClass = container.Resolve<MyClass>();
            Assert.IsNotNull(myClass);
        }
        /// <summary>
        /// 注册程序集下的所有指定类型的类
        /// </summary>
        public static void register_assembly()
        {
            var builder = new ContainerBuilder();
            builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).
                Where(t => t.Name.EndsWith("Repository")).
                AsImplementedInterfaces();

            IContainer container = builder.Build();
            var repository = container.Resolve<IRepository>();
            Assert.IsNotNull(repository);
        }
    }

    public class MyClass : IMyInterface
    {
        public MyClass()
        {
        }
        public MyClass(MyParameter parameter)
        {
        }

        public MyProperty Property { get; set; }
    }

    public class MyParameter
    {

    }

    public class MyProperty
    {

    }

    public interface IMyInterface
    {
    }

    public interface IRepository
    {
    }

    public class TestRepository : IRepository
    {
    }

    public class DbRepository : IRepository
    {
    }

    public class MyInstance
    {
        private static readonly Lazy<MyInstance> lazy = new Lazy<MyInstance>(() => new MyInstance());

        private MyInstance()
        {
        }

        public static MyInstance Instance
        {
            get { return lazy.Value; }
        }
    }

    public class MyList<T>
    {
    }
}
